﻿using System.Reflection;
using NLite.Reflection.Internal;
using System;

namespace NLite.Reflection
{
    /// <summary>
    /// 函数委托
    /// </summary>
    /// <param name="target">目标对象</param>
    /// <param name="arguments">函数参数</param>
    /// <returns>函数返回值</returns>
    public delegate object Func(object target, params object[] arguments);
    /// <summary>
    /// 过程委托
    /// </summary>
    /// <param name="target">目标对象</param>
    /// <param name="arguments">过程参数</param>
    public delegate void Proc(object target, params object[] arguments);


    /// <summary>
    /// 访问器委托
    /// </summary>
    /// <param name="target">目标对象</param>
    /// <returns></returns>
    public delegate object Getter(object target);

    /// <summary>
    /// 设置器委托
    /// </summary>
    /// <param name="target">目标对象</param>
    /// <param name="value">设置器参数</param>
    public delegate void Setter(object target, object value);

    /// <summary>
    /// 构造函数委托
    /// </summary>
    /// <param name="arguments">构造函数参数列表</param>
    /// <returns>返回创建的对象</returns>
    public delegate object ConstructorHandler(params object[] arguments);


    /// <summary>
    /// 动态方法工厂
    /// </summary>
    public static class DynamicMethodFactory
    {
        /// <summary>
        /// 得到过程委托
        /// </summary>
        /// <param name="method">方法对象</param>
        /// <returns>返回过程委托</returns>
        public static Proc GetProc(this System.Reflection.MethodInfo method)
        {
            var proc = method.DeclaringType.IsValueType
                 ? (target, args) => method.Invoke(target, args)
                 : DefaultDynamicMethodFactory.CreateProcMethod(method);


            return (target, args) =>
                {
                    try
                    {
                        proc(target, args);
                    }
                    catch (TargetInvocationException ex)
                    {
                        throw ex.InnerException.Handle();
                    }
                    catch (Exception ex)
                    {
                        throw ex.Handle();
                    }
                };
        }

        /// <summary>
        /// 得到函数委托
        /// </summary>
        /// <param name="method">方法对象</param>
        /// <returns>返回函数委托</returns>
        public static Func GetFunc(this System.Reflection.MethodInfo method)
        {
            var func = method.DeclaringType.IsValueType 
                ? (target,args)=>method.Invoke(target,args)
                : DefaultDynamicMethodFactory.CreateFuncMethod(method);

            return (target, args) =>
                {
                    try
                    {
                        return func(target, args);
                    }
                    catch (TargetInvocationException ex)
                    {
                        throw ex.InnerException.Handle();
                    }
                    catch (Exception ex)
                    {
                        throw ex.Handle();
                    }
                };
        }

        /// <summary>
        /// 得到构造函数委托
        /// </summary>
        /// <param name="constructor">构造函数</param>
        /// <returns>返回构造函数委托</returns>
        public static ConstructorHandler GetCreator(this System.Reflection.ConstructorInfo constructor)
        {
            ConstructorHandler ctor = constructor.DeclaringType.IsValueType ? 
                (args)=>constructor.Invoke(args)
                : DefaultDynamicMethodFactory.CreateConstructorMethod(constructor);

            ConstructorHandler handler = args =>
                {
                    try
                    {
                        return ctor(args);
                    }
                    catch (TargetInvocationException ex)
                    {
                        throw ex.InnerException.Handle();
                    }
                    catch (Exception ex)
                    {
                        throw ex.Handle();
                    }
                };

            return handler;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public static Getter GetGetter(this System.Reflection.MemberInfo member)
        {

            Getter getter = null;
            if (member.DeclaringType.IsValueType)
            {
                switch (member.MemberType)
                {
                    case MemberTypes.Field:
                        getter = (target) => (member as FieldInfo).GetValue(target);
                        break;
                    case MemberTypes.Property:
                        getter = (target) => (member as PropertyInfo).GetValue(target, null);
                        break;
                    case MemberTypes.Method:
                        getter = (target) => (member as MethodInfo).Invoke(target, new object[] { });
                        break;
                }

            }
            else
                getter = DefaultDynamicMethodFactory.CreateGetter(member);

            return target =>
            {
                try
                {
                    return getter(target);
                }
                catch (TargetInvocationException ex)
                {
                    throw ex.InnerException.Handle();
                }
                catch (Exception ex)
                {
                    throw ex.Handle();
                }
            };
        }

        /// <summary>
        /// 得到设置器委托
        /// </summary>
        /// <param name="member">成员</param>
        /// <returns>返回设置器委托</returns>
        public static Setter GetSetter(this System.Reflection.MemberInfo member)
        {
            Setter setter = null;
            if (member.DeclaringType.IsValueType)
            {
                switch (member.MemberType)
                {
                    case MemberTypes.Field:
                        setter = (target, value) => (member as FieldInfo).SetValue(target, value);
                        break;
                    case MemberTypes.Property:
                        setter = (target, value) => (member as PropertyInfo).SetValue(target, value,null);
                        break;
                    case MemberTypes.Method:
                        setter = (target, value) => (member as MethodInfo).Invoke(target, new object[] { value });
                        break;
                }
               
            }
            else
                setter = DefaultDynamicMethodFactory.CreateSetter(member);

            return (target,value) =>
            {
                try
                {
                    if(setter != null)
                        setter(target,value);
                }
                catch (TargetInvocationException ex)
                {
                    throw ex.InnerException.Handle();
                }
                catch (Exception ex)
                {
                    throw ex.Handle();
                }
            };
        }
    }
}
